repo: Expose dfd_as_file()
authorColin Walters <walters@verbum.org>
Tue, 21 Sep 2021 12:59:17 +0000 (08:59 -0400)
committerColin Walters <walters@verbum.org>
Fri, 6 May 2022 16:53:57 +0000 (12:53 -0400)
The `dfd()` API returns just an integer.  Add a safe API that
makes a copy of the fd.  What we really want here is `BorrowedFd` from
https://github.com/rust-lang/rfcs/blob/master/text/3128-io-safety.md
but that isn't here yet.

rust-bindings/rust/src/repo.rs
rust-bindings/rust/tests/repo/mod.rs

index d6ffeb41f5e8e4ea05e534440f506854531e56b9..3b4961cff4f61da38654a5636fdceb5b1a8a8d1e 100644 (file)
@@ -40,6 +40,23 @@ impl Repo {
         Repo::new(&gio::File::for_path(path.as_ref()))
     }
 
+    /// Return a copy of the directory file descriptor for this repository.
+    #[cfg(any(feature = "v2016_4", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v2016_4")))]
+    pub fn dfd_as_file(&self) -> std::io::Result<std::fs::File> {
+        use std::os::unix::prelude::FromRawFd;
+        use std::os::unix::prelude::IntoRawFd;
+        unsafe {
+            // A temporary owned file instance
+            let dfd = std::fs::File::from_raw_fd(self.dfd());
+            // So we can call dup() on it
+            let copy = dfd.try_clone();
+            // Now release our temporary ownership of the original
+            let _ = dfd.into_raw_fd();
+            Ok(copy?)
+        }
+    }
+
     /// Find all objects reachable from a commit.
     pub fn traverse_commit<P: IsA<gio::Cancellable>>(
         &self,
index 6bf045b62f044c9badcb46184133396e6fc40bf1..6f3100aa6dc54e59de6bcfff76861504abb4f0f3 100644 (file)
@@ -106,6 +106,17 @@ fn should_write_content_to_repo() {
     }
 }
 
+#[test]
+#[cfg(feature = "v2016_4")]
+fn repo_file() {
+    use std::os::unix::fs::MetadataExt;
+    let test_repo = TestRepo::new();
+    let m1 = test_repo.repo.dfd_as_file().unwrap().metadata().unwrap();
+    let m2 = test_repo.repo.dfd_as_file().unwrap().metadata().unwrap();
+    assert_eq!(m1.dev(), m2.dev());
+    assert_eq!(m1.ino(), m2.ino());
+}
+
 fn copy_file(src: &TestRepo, dest: &TestRepo, obj: &ObjectName) {
     let (stream, len) = src
         .repo